﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Threading;

namespace Server
{

    /// <summary>
    /// 微软自带的SocketServer
    /// </summary>
    public class SocketServerHelper
    {
        public int ID { get; set; }
        /// <summary>
        /// 服务器端IP
        /// </summary>
        public string _ServerIP;

        /// <summary>
        /// 服务器端端口
        /// </summary>
        public int _ServerPort;

        /// <summary>
        /// 监听个数
        /// </summary>
        public int _ListCount;

        /// <summary>
        /// 是否为任意服务器端IP
        /// </summary>
        public bool _AnyServerIP;

        /// </summary>
        /// 处理连接请求的线程
        /// </summary>
        private Thread acceptConnectReqThd;

        /// </summary>
        /// socket对象
        /// </summary>
        Socket _Server;

        /// <summary>
        /// 客户端在线字典
        /// </summary>
        Dictionary<string, Socket> ClientList = new Dictionary<string, Socket>();

        /// <summary>
        /// 在线客户端字符串(存放在在线事件中)
        /// </summary>
        List<string> ClientListKey = new List<string>();

        /// <summary>
        /// 客户端标识注册表
        /// </summary>
        List<SocketData> SocketRegister = new List<SocketData>();
        /// <summary>
        /// 线程循环状态
        /// </summary>
        CancellationTokenSource ThreadState;

        /// <summary>
        /// 接收事件
        /// </summary>
        public event Action<string, string> ReciveEvent;

        /// <summary>
        /// 在线事件
        /// </summary>
        public event Action<List<string>> ClientOlinEvent;
        /// <summary>
        /// 在线事件
        /// </summary>
        public event Action<List<SocketData>> ClientOlinAtEvent;
        /// <summary>
        /// 操作在线字典锁
        /// </summary>
        object WorkDictionaryList = new object();
        public SocketServerHelper(string ServerIP, int ServerPort, int ListCount, bool AnyServerIP = false)
        {
            _ServerIP = ServerIP;
            _ServerPort = ServerPort;
            _ListCount = ListCount;
            _AnyServerIP = AnyServerIP;
        }

        public bool IsOpen { get; set; }

        /// <summary>
        /// 是否连接指定客户端名称(不能搞频率调用)
        /// </summary>
        /// <param name="SocketName"></param>
        /// <returns></returns>
        public bool IsConnectedAt(string SocketName)
        {
            //查询存在列表
            SocketData socketData = SocketRegister.Where(t => t.SocketName == SocketName).FirstOrDefault();
            if (socketData != null)
            {
                return IsConnected(socketData.IP, socketData.Port.ToString());
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 是否连接(不能搞频率调用)
        /// </summary>
        /// <returns></returns>
        public bool IsConnected(string TargetIp, string TargetPort, bool IpDefault = false, bool PortDefault = false)
        {
            if (_Server == null)
            {
                return false;
            }
            bool blockingState = _Server.Blocking;
            try
            {
                bool Exist = false;
                string Index = "";
                if (!IpDefault && PortDefault)
                {
                    if (ClientList.Where(x => x.Key.Split(':')[0] == TargetIp) != null)
                    {
                        Index = ClientList.Where(x => x.Key.Split(':')[0] == TargetIp).FirstOrDefault().Key.ToString();
                    }
                    else
                    {
                        return false;
                    }

                }
                else if (!IpDefault && !PortDefault)
                {
                    if (ClientList.Where(x => x.Key == TargetIp + ":" + TargetPort).Count() > 0)
                    {
                        Index = ClientList.Where(x => x.Key == TargetIp + ":" + TargetPort).FirstOrDefault().Key.ToString();

                    }
                    else
                    {
                        return false;
                    }

                }
                else if (IpDefault && !PortDefault)
                {
                    if (ClientList.Where(x => x.Key.Split(':')[1] == TargetPort).Count() > 0)
                    {
                        Index = ClientList.Where(x => x.Key.Split(':')[1] == TargetPort).FirstOrDefault().Key.ToString();
                    }
                    else
                    {
                        return false;
                    }

                }
                else
                {
                    return false;
                }
                if (Index == "")
                {
                    Exist = false;
                }
                else
                {
                    Exist = true;
                }
                if (Exist == true)
                {
                    byte[] tmp = new byte[1];
                    _Server.Blocking = false;
                    if (ClientList.ContainsKey(Index))
                    {
                        ClientList[Index].Send(tmp, 0, 0);
                        return true;
                    }
                    else
                    {
                        return false;
                    }

                }
                else
                {
                    return false;
                }

            }
            catch (SocketException e)
            {
                // 产生 10035 == WSAEWOULDBLOCK 错误，说明被阻止了，但是还是连接的
                if (e.NativeErrorCode.Equals(10035))
                    return true;
                else
                    return false;
            }
            finally
            {
                if (_Server != null)
                {
                    _Server.Blocking = blockingState;    // 恢复状态
                }
            }
        }
        /// <summary>
        /// 连接请求的处理函数
        /// </summary>
        /// <param name="_socket"></param>
        private void AcceptConnectReqHandler()
        {
            try
            {
                while (!ThreadState.IsCancellationRequested)
                {
                    Thread.Sleep(50);
                    //获取客户端socket。Accept方法处理任何传入的连接请求，并返回可用于与远程主机通信数据的Socket对象，即客户端的socket。
                    //这一句话会卡主线程。只要没有新的链接进来，就会一直卡主不动（等待中）。
                    //收到连接事件后，会往下执行，通过while又回到这里继续等待
                    Socket clientSocket = _Server.Accept();

                    if (ClientList.ContainsKey(clientSocket.RemoteEndPoint.ToString()))//已经存在要删除
                    {
                        lock (WorkDictionaryList)
                        {
                            ClientList.Remove(clientSocket.RemoteEndPoint.ToString());
                            ClientListKey.RemoveAt(ClientListKey.IndexOf(clientSocket.RemoteEndPoint.ToString()));
                            ClientOlinEvent?.Invoke(ClientListKey.Select(t => t).ToList());
                            string[] EndPoints = clientSocket.RemoteEndPoint.ToString().Split(':');
                            //删除拥有的
                            if (SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList().Count > 0)
                            {
                                foreach (var item in SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList())
                                {
                                    SocketRegister.Remove(item);
                                }

                            }
                            ClientOlinAtEvent?.Invoke(SocketRegister);
                        }
                    }
                    lock (WorkDictionaryList)
                    {
                        ClientList.Add(clientSocket.RemoteEndPoint.ToString(), clientSocket);//新增客户端信息到字典中
                        ClientListKey.Add(clientSocket.RemoteEndPoint.ToString());
                        ClientOlinEvent?.Invoke(ClientListKey.Select(t => t).ToList());
                    }

                    //创建接受客户端消息的线程
                    Thread acceptMsgReqThd = new Thread(ReciveMsgReqHandler);
                    acceptMsgReqThd.IsBackground = true;
                    acceptMsgReqThd.Start(clientSocket);

                }
            }
            catch
            {
                //ClientList.Clear();//删除所有客户端字典中信息
            }
        }

        /// <summary>
        /// 接收客户端socket消息
        /// </summary>
        /// <param name="_socket"></param>
        private void ReciveMsgReqHandler(object _socket)
        {
            Socket clientSocket = (Socket)_socket;
            try
            {
                bool Break = false;
                while (!ThreadState.IsCancellationRequested)
                {
                    //客户端连接成功后，接受来自客户端的消息
                    if (clientSocket == null)
                    {
                        continue;
                    }
                    byte[] buffer = new byte[1024 * 1024];  //数据缓冲区。
                                                            //实际接收到的有效字节数
                                                            //Receive也是个卡线程的方法
                                                            //int dataLength = clientSocket.Receive(buffer);
                    int dataLength = clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);

                    //如果客户端关闭，发送的数据就为空，就跳出循环
                    if (dataLength == 0)
                    {

                        if (ClientList.ContainsKey(clientSocket.RemoteEndPoint.ToString()))
                        {
                            lock (WorkDictionaryList)
                            {
                                //ClientList[clientSocket.RemoteEndPoint.ToString()].Close();
                                ClientList.Remove(clientSocket.RemoteEndPoint.ToString());//删除客户端字典中信息
                                ClientListKey.RemoveAt(ClientListKey.IndexOf(clientSocket.RemoteEndPoint.ToString()));
                                string[] EndPoints = clientSocket.RemoteEndPoint.ToString().Split(':');
                                //删除拥有的
                                if (SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList().Count > 0)
                                {
                                    foreach (var item in SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList())
                                    {
                                        SocketRegister.Remove(item);
                                    }

                                }
                                if (!Break)
                                {
                                    ClientOlinEvent?.Invoke(ClientListKey.Select(t => t).ToList());
                                    ClientOlinAtEvent?.Invoke(SocketRegister);
                                }
                            }
                        }
                        clientSocket.Shutdown(SocketShutdown.Both);
                        //ps.StopServerConnet(clientSocket);
                        clientSocket.Close(100);
                        clientSocket.Dispose();
                        Break = true;
                    }

                    if (Break)
                    {
                        break;
                    }
                    //假设收到的是个字符串（先这么假定），转成字符串处理
                    string strMsg = Encoding.UTF8.GetString(buffer, 0, dataLength);
                    string[] Message = strMsg.Split(',');//进行获取对方标识身份
                    if (Message.Count() == 2)
                    {
                        if (Message[0] == "SocketName")
                        {
                            //删除曾经拥有的
                            if (SocketRegister.Where(t => t.SocketName.Contains(Message[1])).ToList().Count > 0)
                            {
                                foreach (var item in SocketRegister.Where(t => t.SocketName.Contains(Message[1])).ToList())
                                {
                                    SocketRegister.Remove(item);
                                }

                            }
                            string[] EndPoints = clientSocket.RemoteEndPoint.ToString().Split(':');
                            SocketRegister.Add(new SocketData()
                            {
                                IP = EndPoints[0],
                                Port = Convert.ToInt32(EndPoints[1]),
                                SocketName = Message[1]
                            });
                            ClientOlinAtEvent?.Invoke(SocketRegister);
                            continue;
                        }
                    }
                    ReciveEvent?.Invoke(clientSocket.RemoteEndPoint.ToString(), strMsg);//触发委托
                }
                //中止当前线程
                //Thread.CurrentThread.Abort();
            }
            catch (SocketException e)
            {
                if (!IsOpen)
                {
                    return;
                }
                if (e.ErrorCode == 10053)
                {
                    return;
                }
                if (ClientList.Count != 0)
                {
                    if (ClientList.ContainsKey(clientSocket.RemoteEndPoint.ToString()))
                    {
                        lock (WorkDictionaryList)
                        {
                            //ClientList[clientSocket.RemoteEndPoint.ToString()].Close();
                            ClientList.Remove(clientSocket.RemoteEndPoint.ToString());//删除客户端字典中信息
                            ClientListKey.RemoveAt(ClientListKey.IndexOf(clientSocket.RemoteEndPoint.ToString()));
                            ClientOlinEvent?.Invoke(ClientListKey.Select(t => t).ToList());
                            string[] EndPoints = clientSocket.RemoteEndPoint.ToString().Split(':');
                            //删除拥有的z
                            if (SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList().Count > 0)
                            {
                                foreach (var item in SocketRegister.Where(t => t.IP == EndPoints[0] && t.Port == Convert.ToInt32(EndPoints[1])).ToList())
                                {
                                    SocketRegister.Remove(item);
                                }

                            }
                            ClientOlinAtEvent?.Invoke(SocketRegister);
                        }

                    }
                }
                //clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close(100);
                clientSocket.Dispose();
                SocketException socketExp = e as SocketException;
                if (socketExp != null && socketExp.NativeErrorCode == 10054)//socket客户端关闭
                {

                }
                else//接受消息异常
                {

                }
                //中止当前线程
                // Thread.CurrentThread.Abort();
            }
        }
        /// <summary>
        /// 启动服务器
        /// </summary>
        public bool Start()
        {
            try
            {
                _Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //_Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                //获取IP
                IPAddress ip = IPAddress.Parse(_ServerIP);
                //创建端口号
                IPEndPoint port;
                if (_AnyServerIP == false)
                {
                    port = new IPEndPoint(ip, _ServerPort);
                }
                else
                {
                    port = new IPEndPoint(IPAddress.Any, _ServerPort);
                }
                //监听
                _Server.Bind(port);
                _Server.Listen(_ListCount);  //设定最大的挂起长度
                if ((acceptConnectReqThd == null || !acceptConnectReqThd.IsAlive) && !IsOpen)
                {
                    //新建线程来处理连接请求
                    acceptConnectReqThd = new Thread(AcceptConnectReqHandler);
                    acceptConnectReqThd.IsBackground = true;
                    ThreadState = new CancellationTokenSource();//线程循环状态
                    acceptConnectReqThd.Start();  //把socket对象当做参数传递给到线程里面的方法
                    IsOpen = true;
                    return true;
                }
                else
                {
                    //"已经连接,无需再次开启服务";
                    return false;
                }
            }
            catch (Exception ex)
            {
                IsOpen = false;
                //throw new Exception("服务器本机没有该端口可用");
                return false;
            }
        }

        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <returns></returns>
        public bool Close()
        {
            try
            {
                if (IsOpen && !(_Server == null))
                {
                    IsOpen = false;
                    ThreadState.Cancel();//结束线程循环
                                         //acceptConnectReqThd.Abort();//关闭监听线程

                    //Thread.Sleep(500);
                    foreach (var item in ClientList)
                    {
                        item.Value.Close();
                        item.Value.Dispose();
                    }

                    ClientList.Clear();
                    ClientListKey.Clear();
                    SocketRegister.Clear();
                    ClientOlinEvent?.Invoke(ClientListKey.Select(t => t).ToList());
                    ClientOlinAtEvent?.Invoke(SocketRegister);
                    _Server.Close();//关闭对象
                    _Server.Dispose();
                    //删除拥有
                    _Server = null;

                    return true;
                }
                else
                {
                    IsOpen = false;
                    // throw new Exception("未连接,无需关闭服务");
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// 发送信息指定客户端名称
        /// </summary>
        /// <param name="SocketName"></param>
        /// <param name="Message"></param>
        /// <returns></returns>
        public bool SendMessageAt(string SocketName, string Message)
        {
            //查询存在列表
            SocketData socketData = SocketRegister.Where(t => t.SocketName == SocketName).FirstOrDefault();
            if (socketData != null)
            {
                return SendMessage(socketData.IP, socketData.Port.ToString(), Message);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 发送信息
        /// </summary>
        /// <param name="TargetIp"></param>
        /// <param name="TargetPort"></param>
        /// <param name="Message"></param>
        /// <param name="IpDefault"></param>
        /// <param name="PortDefault"></param>
        /// <returns></returns>
        public bool SendMessage(string TargetIp, string TargetPort, string Message, bool IpDefault = false, bool PortDefault = false)
        {
            try
            {
                bool Exist = false;
                string Index = "";
                if (!IpDefault && PortDefault)
                {
                    if ((from q in ClientList.Where(x => x.Key.Split(':')[0] == TargetIp) select q).Count() > 0)
                    {
                        Index = (from q in ClientList.Where(x => x.Key.Split(':')[0] == TargetIp) select q.Key).First();
                    }
                    else
                    {
                        return false;
                    }
                }
                else if (!IpDefault && !PortDefault)
                {
                    if ((from q in ClientList.Where(x => x.Key == TargetIp + ":" + TargetPort) select q).Count() > 0)
                    {
                        Index = (from q in ClientList.Where(x => x.Key == TargetIp + ":" + TargetPort) select q.Key).FirstOrDefault().ToString();

                    }
                    else
                    {
                        return false;
                    }
                }
                else if (IpDefault && !PortDefault)
                {
                    if ((from q in ClientList.Where(x => x.Key.Split(':')[1] == TargetPort) select q).Count() > 0)
                    {
                        Index = (from q in ClientList.Where(x => x.Key.Split(':')[1] == TargetPort) select q.Key).FirstOrDefault().ToString();
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
                if (Index == "")
                {
                    Exist = false;
                }
                else
                {
                    Exist = true;
                }
                if (Exist)
                {
                    byte[] MessageByte = Encoding.Default.GetBytes(Message);
                    ClientList[Index].Send(MessageByte);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }
    }
    /// <summary>
    /// 套接字注册实体类
    /// </summary>
    public class SocketData
    {
        public string IP { get; set; }
        public int Port { get; set; }
        public string SocketName { get; set; }
    }
}
